import React, {
  forwardRef,
  ReactElement,
  useImperativeHandle,
  useMemo,
  useRef,
  useEffect
} from 'react';
import { Keyboard, View } from 'react-native';
import X5WebView from 'react-native-webview-x5';
import WebView from 'react-native-webview';
import createInvoke, { IMessager } from 'react-native-webview-invoke/native';

import styles from './style';
import {
  submitAnswer,
  setShowProblemWait,
  setSelectedAnswer
} from '../../../../actions';
import { getUserInfo } from '../../../../../../store/user';
import {
  CARD_HEIGHT,
  PROBLEM_TYPE,
  SUBJECT_TYPE,
  UserRole
} from '../../../../constant';
import { isIOS } from '../../../../../../constant';
import {
  ProblemAnswer,
  ProblemDetail
} from '../../../../../../api/common/problem';
import Log from '../../../../../../common/log';
import { getOsVersionIsLow } from '../../../../../../util/osVersion';

const TAG = 'ProblemWebview';

interface ProblemProps {
  problem: ProblemDetail;
  roundId: number;
}

const Problem = (
  { problem, roundId }: ProblemProps,
  ref: any
): ReactElement => {
  const webView = useRef<any>(null);
  const invoke: IMessager = createInvoke((): any =>
    webView && webView.current
      ? webView.current
      : { postMessage: (data: any): void => {} }
  );
  // const invoke: IMessager = createInvoke((): any => webView.current);
  // 提供函数供WebView调用
  const logInWebView = (log: string): void => {
    console.log('RN2WebViewLog logInWebView', log);
    Log.i(TAG, log);
  };
  const setProblemAnswerInWebView = (answer: ProblemAnswer): void => {
    console.log('RN2WebViewLog setProblemAnswerInWebView', answer);
    setSelectedAnswer(answer);
  };
  const submitProblemInWebView = (answer: ProblemAnswer): void => {
    console.log('RN2WebViewLog submitProblemInWebView', answer);
    submitAnswer(roundId, answer, problem.problemType);
  };
  const continueProblemInWebView = (answer: ProblemAnswer): void => {
    console.log('RN2WebViewLog continueProblemInWebView', answer);
    setShowProblemWait(true);
  };
  invoke.define('logInWebView', logInWebView);
  invoke.define('setProblemAnswerInWebView', setProblemAnswerInWebView);
  invoke.define('submitProblemInWebView', submitProblemInWebView);
  invoke.define('continueProblemInWebView', continueProblemInWebView);

  // 调用WebView提供的函数
  const setProblemWebViewInfoInRN = invoke.bind('setProblemWebViewInfoInRN');
  const setHaveSubmitSingleAnswerInRN = invoke.bind(
    'setHaveSubmitSingleAnswerInRN'
  );
  const setSingleAnswerInRN = invoke.bind('setSingleAnswerInRN');
  const setHaveSubmitFillAnswerInRN = invoke.bind(
    'setHaveSubmitFillAnswerInRN'
  );
  const setFillAnswerInRN = invoke.bind('setFillAnswerInRN');
  const setHaveSubmitEnglishFillAnswerInRN = invoke.bind(
    'setHaveSubmitEnglishFillAnswerInRN'
  );
  const setEnglishFillAnswerInRN = invoke.bind('setEnglishFillAnswerInRN');
  const setHaveSubmitWordBlankFillAnswerInRN = invoke.bind(
    'setHaveSubmitWordBlankFillAnswerInRN'
  );
  const setWordBlankFillAnswerInRN = invoke.bind('setWordBlankFillAnswerInRN');
  const setHaveSubmitClozeAnswerInRN = invoke.bind(
    'setHaveSubmitClozeAnswerInRN'
  );
  const setClozeAnswerInRN = invoke.bind('setClozeAnswerInRN');
  const setHaveSubmitReadingAnswerInRN = invoke.bind(
    'setHaveSubmitReadingAnswerInRN'
  );
  const setReadingAnswerInRN = invoke.bind('setReadingAnswerInRN');

  const setHaveSubmitMultiFillAnswerInRN = invoke.bind(
    'setHaveSubmitMultiFillAnswerInRN'
  );
  const setMultiFillAnswerInRN = invoke.bind('setMultiFillAnswerInRN');

  const setFillIsShowKeyBoardInRN = invoke.bind('setFillIsShowKeyBoardInRN');
  const setMultiFillIsShowKeyBoardInRN = invoke.bind(
    'setMultiFillIsShowKeyBoardInRN'
  );

  const update = (
    haveSubmitAnswer: boolean,
    userAnswer: ProblemAnswer
  ): void => {
    if (problem.problemType === PROBLEM_TYPE.Single) {
      setHaveSubmitSingleAnswerInRN(haveSubmitAnswer);
      if (
        userAnswer &&
        userAnswer.answer &&
        userAnswer.answer[0] &&
        haveSubmitAnswer
      ) {
        setSingleAnswerInRN(userAnswer.answer[0]);
      }
    }
    if (
      problem.problemType === PROBLEM_TYPE.Fill &&
      problem.subjectId === SUBJECT_TYPE.Math
    ) {
      setHaveSubmitFillAnswerInRN(haveSubmitAnswer);
      if (userAnswer && userAnswer.answer && haveSubmitAnswer) {
        setFillAnswerInRN(userAnswer.answer);
      }
    }
    if (
      problem.problemType === PROBLEM_TYPE.Fill &&
      problem.subjectId === SUBJECT_TYPE.English
    ) {
      setHaveSubmitEnglishFillAnswerInRN(haveSubmitAnswer);
      if (userAnswer && userAnswer.answer && haveSubmitAnswer) {
        setEnglishFillAnswerInRN(userAnswer.answer);
      }
    }
    if (
      problem.problemType === PROBLEM_TYPE.WordBlankFill &&
      problem.subjectId === SUBJECT_TYPE.English
    ) {
      setHaveSubmitWordBlankFillAnswerInRN(haveSubmitAnswer);
      if (userAnswer && userAnswer.smallAnswers && haveSubmitAnswer) {
        setWordBlankFillAnswerInRN(userAnswer.smallAnswers);
      }
    }
    if (problem.problemType === PROBLEM_TYPE.Cloze) {
      setHaveSubmitClozeAnswerInRN(haveSubmitAnswer);
      if (userAnswer && userAnswer.smallAnswers && haveSubmitAnswer) {
        setClozeAnswerInRN(userAnswer.smallAnswers);
      }
    }
    if (problem.problemType === PROBLEM_TYPE.Reading) {
      setHaveSubmitReadingAnswerInRN(haveSubmitAnswer);
      if (userAnswer && userAnswer.smallAnswers && haveSubmitAnswer) {
        setReadingAnswerInRN(userAnswer.smallAnswers);
      }
    }
    if (
      problem.problemType === PROBLEM_TYPE.WordBlankFill &&
      problem.subjectId === SUBJECT_TYPE.Math
    ) {
      setHaveSubmitMultiFillAnswerInRN(haveSubmitAnswer);
      if (userAnswer && userAnswer.smallAnswers && haveSubmitAnswer) {
        setMultiFillAnswerInRN(userAnswer.smallAnswers);
      }
    }
  };

  useImperativeHandle(ref, (): { [key: string]: any } => {
    return {
      update
    };
  });

  useEffect((): void => {
    const { role } = getUserInfo();
    const isNotStudent = role !== UserRole.Student;
    if (webView.current && setProblemWebViewInfoInRN) {
      setTimeout((): void => {
        setProblemWebViewInfoInRN({
          problem,
          isNotStudent,
          scale: CARD_HEIGHT / 360
        });
      }, 0);
    }
  }, [problem, setProblemWebViewInfoInRN]);

  useEffect((): (() => void) => {
    const setIsShowKeyboard = (isShow: boolean): void => {
      if (
        problem.problemType === PROBLEM_TYPE.Fill &&
        problem.subjectId === SUBJECT_TYPE.Math
      ) {
        setFillIsShowKeyBoardInRN(isShow);
      }
      if (
        problem.problemType === PROBLEM_TYPE.WordBlankFill &&
        problem.subjectId === SUBJECT_TYPE.Math
      ) {
        setMultiFillIsShowKeyBoardInRN(isShow);
      }
    };

    const keyboardWillShowListener = Keyboard.addListener(
      isIOS ? 'keyboardWillShow' : 'keyboardDidShow',
      (): void => setIsShowKeyboard(true)
    );
    const keyboardWillHideListener = Keyboard.addListener(
      isIOS ? 'keyboardWillHide' : 'keyboardDidHide',
      (): void => setIsShowKeyboard(false)
    );
    return (): void => {
      keyboardWillShowListener.remove();
      keyboardWillHideListener.remove();
    };
  }, [
    problem.problemType,
    problem.subjectId,
    setFillIsShowKeyBoardInRN,
    setMultiFillIsShowKeyBoardInRN
  ]);

  const osVersionIsLow = getOsVersionIsLow();

  return useMemo(
    (): ReactElement => (
      <View style={styles.container}>
        {isIOS || osVersionIsLow ? (
          <WebView
            ref={webView}
            style={styles.webview}
            source={{
              uri: `http://127.0.0.1:21994/videos/problem/build/aikidProblem/index.html`
            }}
            onMessage={invoke.listener}
          />
        ) : (
          <X5WebView
            ref={webView}
            style={styles.webview}
            source={{
              uri: `http://127.0.0.1:21994/videos/problem/build/aikidProblem/index.html`
            }}
            onMessage={invoke.listener}
            androidLayerType="software"
          />
        )}
      </View>
    ),
    [invoke.listener, osVersionIsLow]
  );
};

export default forwardRef(Problem);
